package org.slf4jx.core;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.slf4j.Logger;
import org.slf4j.MDC;

import java.lang.reflect.Method;
import java.util.*;

/**
 * Logger的包装代理类
 * @author jjliu
 * @date 2023/1/13
 */
public class Slf4jxLoggerCglibProxy implements MethodInterceptor {
    /** 包装的logger */
    Logger logger;

    public Object getProxy(Logger logger){
        this.logger = logger;
        //设置需要创建子类的类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Logger.class);
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    protected Slf4jxLevelEnum getLevel(Logger logger){
         if(logger.isTraceEnabled()){
            return Slf4jxLevelEnum.trace;
        }else if(logger.isDebugEnabled()){
            return Slf4jxLevelEnum.debug;
        }else if(logger.isInfoEnabled()){
            return Slf4jxLevelEnum.info;
        }else if(logger.isWarnEnabled()){
            return Slf4jxLevelEnum.warn;
        }else if(logger.isErrorEnabled()){
            return Slf4jxLevelEnum.error;
        }else{
             // 较为特殊，认为是最低级别控制， 下面就不用调整了
             return Slf4jxLevelEnum.trace;
         }
    };

    @Override
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy proxy) throws Throwable {
        /// 非打印函数，无视
        if(!Slf4jxStaticContext.methodMap.containsKey(method.getName())){
            return proxy.invoke(logger, args);
        }

        //当前打印级别
        Slf4jxLevelEnum curLevelEnum = Slf4jxLevelEnum.of(method.getName());
        // 为空一般不存在
        if(curLevelEnum==null){
            return proxy.invoke(logger, args);
        }
        // 当前级别就可以打印
        if(curLevelEnum.ordinal() >= getLevel(logger).ordinal()){
            return proxy.invoke(logger, args);
        }

        String specifyLevelConfigStr = MDC.get(Slf4jxCons.SLF4JX_MDC_LEVEL);
        /// 线程变量没有指定
        if(Slf4jxUtils.isBlank(specifyLevelConfigStr)){
            return proxy.invoke(logger, args);
        }

        /// 线程变量的指定级别
        List<Map<String,Object>> specifyLevelConfigList = Optional.ofNullable(specifyLevelConfigStr)
                .filter(x-> Slf4jxUtils.isNotBlank(x))
                .map(x-> Slf4jxUtils.setSpecifyLevelConfigList(x))
                .orElse(null);
        /// 没解析出来
        if(Slf4jxUtils.isEmpty(specifyLevelConfigList)){
            return proxy.invoke(logger, args);
        }
        //匹配的指定级别
        Slf4jxLevelEnum specifyLevel = null;
        for(Map<String,Object> pair : specifyLevelConfigList){
            String logName = (String)pair.get(Slf4jxCons.SLF4JX_MDC_NAME);
            Slf4jxLevelEnum slf4jxLevelEnum = (Slf4jxLevelEnum)pair.get(Slf4jxCons.SLF4JX_MDC_VALUE);
            if(Slf4jxCons.SLF4JX_MDC_ALL.equalsIgnoreCase(logName)){
                specifyLevel = slf4jxLevelEnum;
                break;
            }else if(logger.getName().startsWith(logName)){
                specifyLevel = slf4jxLevelEnum;
                break;
            }
        }
        // 没有匹配的 或者 当前级别比指定的还要低，那就没救了
        if(specifyLevel==null || curLevelEnum.ordinal() < specifyLevel.ordinal()){
            return proxy.invoke(logger, args);
        }

        /// 按照最小可输出级别进行输出
        Method loggerLevelMethod = Slf4jxStaticContext.methodMap.getOrDefault(getLevel(logger).name(), (Map<String,Method>)Collections.EMPTY_MAP)
                .get(Slf4jxUtils.parametersAsString(method));
        /// 为空一般不存在
        if(loggerLevelMethod==null){
            return proxy.invoke(logger, args);
        }
        /// 调整到合适的级别进行输出
        Object result = loggerLevelMethod.invoke(logger, args);
        return result;
    }
}